
module	mbox.Reader ;

import	mbox.Types ;



struct Smtp_Reader {
	static ServerSocket	_soc ;
	
	static  void Init() {
		try{
			_soc =  new ServerSocket(new InternetAddress( MyConf.ip , MyConf.port ) ) ;
		}catch(Object e) {
			Stdout("Unable to bind socket to ")(MyConf.ip )(":")(MyConf.port)("\n").flush;
			Cin.get;
			exit(1);
		}
		Stdout.formatln("SMTP Server Listen on {}:{}",  MyConf.ip , MyConf.port );
	}
	
	static void Start() {
		MyDns.Start;
		Smtp_Sender.Start;
		
		while( MyBox.isRunning.load() ){
			scope Smtp_Reader*  p	= new Smtp_Reader;
			p.ls			= LineSocket.Init(  _soc.accept()  ); 
			p._start		= Clock.now ;
			p.loop;
			delete p ;
		}
		Stdout.formatln("Reader Thread Finish.").flush;
	}

        LineSocket*	ls ;
	
	bool			isLoop ;
	bool			isDone ;
	char[]		_helo ;
	char[]		_from ;
	char[][]		_to ;
	Array			_body ;
	Time			_start ;
	
	void loop(){
		scope(exit){
			save;
		}
		if( !hello() ) return ;
		
		while( isLoop ){
			char[] ln	= ls.get ;
			int i		= find(ln, ':');
			if( i < 0 || i == ln.length ) {
				if( ln == `DATA` ){
					readBody(); 
					continue ;
				}else if( ln == `QUIT`) {
					ls.put(`221 Bye`);
					return ;
				}else{
					version(DEV){
						Stdout.formatln("{}:{}	unhandle end.", __FILE__, __LINE__ );
					}
					return ;
				}
			}
			char[] key	= ln[0..i] ;
			char[] val	= ln[i+1..$] ;
			if( key == `MAIL FROM` ){
				from(val);
			}else if( key == `RCPT TO`) {
				sendTo(val);
			}else {
				version(DEV) {
					Stdout.formatln("{}:{}	unhandle key.", __FILE__, __LINE__ );
				}
			}
		}
		
	}
	
	void readBody() {
		static const char[] mail_end	= "\r\n.\r\n";
		ls.put(`354 Start mail input; end with <CRLF>.<CRLF>`);
		_body		= new Array(1024, 1024 );
		ubyte[128]	tmp ;
		while( true ) {
			int i	= ls.read(tmp);
			if( i < 1 || i > tmp.length ){
				break ;
			}
			_body( tmp[0..i] );
			auto _tmp	= cast(char[]) _body.slice ;
			if( _tmp.length  <   mail_end.length  ){
				continue ;
			}
			if( _tmp[ $- mail_end.length.. $] == mail_end ){
				isDone	= true ;
				break;
			}
		}
		version(DEV){
			Stdout.formatln("{}", cast(char[]) _body.slice );
		}
		ls.put(`250 OK`);
	}
	
	void from(char[] val ){
		val	= Txt.trim(val) ;
		if( val.length < 1 ){
			isLoop	= false ;
			return ;
		}
		_from	= val.dup ;
		ls.put("250 OK Sender " ~ val ~  " is allowed");
	}
	
	void sendTo(char[] val ){
		val	= Txt.trim(val);
		if( val.length < 1 ){
			isLoop	= false ;
			return ;
		}
		_to	~= val.dup ;
		ls.put("250 OK Send to " ~ val ~  " is allowed");
	}
	
	bool hello() {
		ls.put("220 SMTP Server Ready.");
		char[] hello	= ls.get ;
		int i	= find(hello, ' ');
		if( hello[0..i] != `HELO` ){
			return false;
		}
		ls.put("250 SMTP localhost (127.0.0.1), pleased to meet you");
		_helo	= hello[i+1..$];
		isLoop	= true ;
		return true ;
	}
	
	void save() {
		ls.close ;
		version(DEV){
			Stdout.formatln("{}ms, {}", ( Clock.now - _start).millis, isDone).flush;
		}
		if( isDone ){
			MyBox.push(this);
		}
	}

}